/*
 * Copyright (C), 2002-2016, 苏宁易购电子商务有限公司
 * FileName: TimeMachineServiceImpl.java
 * Author:   15050536
 * Date:     2016年12月6日 下午7:46:58
 * Description: //模块目的、功能描述      
 * History: //修改记录
 * <author>      <time>      <version>    <desc>
 * 修改人姓名             修改时间            版本号                  描述
 */
package com.suning.sawp.service.impl.tm;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Seconds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.gson.Gson;
import com.suning.nsfuaa.employee.EmployeeService;
import com.suning.nsfuaa.employee.dto.Employee;
import com.suning.rsf.consumer.ServiceLocator;
import com.suning.sawp.constants.TMConstants;
import com.suning.sawp.intf.dao.tm.TimeMachineDao;
import com.suning.sawp.intf.esb.MemberInfoService;
import com.suning.sawp.intf.promotion.InnerCouponService;
import com.suning.sawp.intf.tm.TimeMachineService;
import com.suning.sawp.intf.tm.vo.CouponInfoVo;
import com.suning.sawp.intf.tm.vo.EmployeeHireInfoVo;
import com.suning.sawp.intf.tm.vo.MemberInfoVo;
import com.suning.sawp.intf.tm.vo.ThisYearSaleInfoVo;
import com.suning.sawp.intf.tm.vo.TimeMachineVo;
import com.suning.sawp.intf.tm.vo.TotalSaleInfoVo;
import com.suning.sawp.po.tm.EmployeeCategoryInfo;
import com.suning.sawp.po.tm.EmployeeExpensiveSaleInfo;
import com.suning.sawp.po.tm.EmployeeFirstSaleInfo;
import com.suning.sawp.po.tm.EmployeeHireInfo;
import com.suning.sawp.po.tm.EmployeeMemberInfo;
import com.suning.sawp.po.tm.EmployeeTotalSaleInfo;
import com.suning.sawp.service.util.NumberUtils;
import com.suning.sawp.service.util.RedisCacheUtils;
import com.suning.vgs.follow.remote.intf.StoreManRemoteService;
import com.suning.vgs.follow.remote.store.StoreManEbuyAccount;

/**
 * 时光机 查询数据给前端 service 实现类
 *
 * @author 15050536 石键平
 */
@Service
public class TimeMachineServiceImpl implements TimeMachineService {

	private Logger LOGGER = LoggerFactory.getLogger(TimeMachineServiceImpl.class);

	@Autowired
	private TimeMachineDao timeMachineDao;

	@Autowired
	MemberInfoService memberInfoService;

	private EmployeeService employeeService = ServiceLocator.getService(EmployeeService.class, "");

	@Resource
	private StoreManRemoteService storeManRemoteService;

	@Resource
	private InnerCouponService innerCouponService;

	@Resource
	private RedisCacheUtils cacheUtils;

	private Gson gson = new Gson();

	/**
	 * 创建一个线程池
	 */
	private ExecutorService pool = Executors.newFixedThreadPool(10);

	@Override
	public String findTimeMachineData(String employeeId) {
		// 先从缓存读取数据 绑定易购账号之后，记得更新缓存
		String data = findDataFromCache(employeeId);
		if (StringUtils.isNotEmpty(data)) {
			LOGGER.debug("{}对应的时光机数据为：{}", employeeId, data);
			return data;
		}
		// 查库，入缓存，返回
		return findDataFromDB(employeeId);

	}

	/**
	 * 
	 * 直接从缓存读取员工入职信息
	 *
	 * @param employeeId
	 *            工号
	 * @return
	 */
	private String findDataFromCache(String employeeId) {
		// 每个员工对应一份缓存数据
		String data = cacheUtils.get(TMConstants.TIME_MACHINE_KEY + employeeId);
		// 缓存里没数据，返回null,去库里捞数据
		if (StringUtils.isEmpty(data)) {
			return null;
		}
		// 缓存中的数据，有可能是直接跑ftp文件得到的，故需要把一些获取不到的数据重新组装
		TimeMachineVo tmVo = fillDataInCache(data, employeeId);
		// 返回null，查库去
		if (tmVo == null) {
			return null;
		}
		// 新变更的数据入缓存
		data = gson.toJson(tmVo);
		// data入缓存
		saveDateInCache(employeeId, data);
		return data;
	}

	/**
	 * 
	 * 数据库读取员工入职信息
	 *
	 * @param employeeId
	 * @return
	 */
	private String findDataFromDB(String employeeId) {

		// 入职信息任务
		FutureTask<EmployeeHireInfo> taskA = new FutureTask<EmployeeHireInfo>(new TaskA(timeMachineDao, employeeId));

		// 首单任务
		FutureTask<EmployeeFirstSaleInfo> taskB = new FutureTask<EmployeeFirstSaleInfo>(new TaskB(timeMachineDao, employeeId));

		// 销售总量 任务
		FutureTask<EmployeeTotalSaleInfo> taskC = new FutureTask<EmployeeTotalSaleInfo>(new TaskC(timeMachineDao, employeeId));

		// 16年最贵的一单 任务
		FutureTask<EmployeeExpensiveSaleInfo> taskD = new FutureTask<EmployeeExpensiveSaleInfo>(new TaskD(timeMachineDao, employeeId));

		// 16年销售记录 按类目分组 任务
		FutureTask<EmployeeCategoryInfo> taskE = new FutureTask<EmployeeCategoryInfo>(new TaskE(timeMachineDao, employeeId));

		// 16年接待会员信息 任务
		FutureTask<List<EmployeeMemberInfo>> taskF = new FutureTask<List<EmployeeMemberInfo>>(new TaskF(timeMachineDao, employeeId));

		// 查询券信息
		FutureTask<CouponInfoVo> taskG = new FutureTask<CouponInfoVo>(new TaskG(innerCouponService, employeeId));

		// 执行线程
		pool.execute(taskA);
		pool.execute(taskB);
		pool.execute(taskC);
		pool.execute(taskD);
		pool.execute(taskE);
		pool.execute(taskF);
		pool.execute(taskG);

		try {
			EmployeeHireInfo hire = taskA.get(TMConstants.TASK_TIMEOUT, TimeUnit.SECONDS);
			EmployeeFirstSaleInfo firstSale = taskB.get(TMConstants.TASK_TIMEOUT, TimeUnit.SECONDS);
			EmployeeTotalSaleInfo totalSale = taskC.get(TMConstants.TASK_TIMEOUT, TimeUnit.SECONDS);
			EmployeeExpensiveSaleInfo expensiveSale = taskD.get(TMConstants.TASK_TIMEOUT, TimeUnit.SECONDS);
			EmployeeCategoryInfo categoryInfo = taskE.get(TMConstants.TASK_TIMEOUT, TimeUnit.SECONDS);
			List<EmployeeMemberInfo> memberInfos = taskF.get(TMConstants.TASK_TIMEOUT, TimeUnit.SECONDS);
			CouponInfoVo couponVo = taskG.get(TMConstants.TASK_TIMEOUT, TimeUnit.SECONDS);

			TimeMachineVo timeMachine = generateTimeMachineVo(hire, firstSale, totalSale, expensiveSale, categoryInfo, memberInfos, couponVo);
			// 存姓名
			Employee storeMan = employeeService.queryEmployeeBasicInfo(employeeId);
			if (storeMan != null) {
				String employeeName = storeMan.getEmployeeName();
				timeMachine.getUserInfo().setName(employeeName);
			}
			// 查询个人的易购账号
			StoreManEbuyAccount account = findEbuyNoByEmployeeId(employeeId);
			if (account != null) {
				timeMachine.getUserInfo().setEbuyNo(account.getMaskeEbuyNo());
			} else {
				timeMachine.getUserInfo().setEbuyNo(StringUtils.EMPTY);
			}
			// 如果有今年数据，且有老用户
			if (timeMachine.getThisYearSaleInfo() != null && timeMachine.getThisYearSaleInfo().getOldCustomer() != null) {
				deleteInvalidCustomData(timeMachine.getThisYearSaleInfo().getOldCustomer());
			}

			String data = gson.toJson(timeMachine);
			// 查询的数据入缓存
			saveDateInCache(employeeId, data);

			return data;

		} catch (Exception e) {
			LOGGER.error("获取时光机数据异常", e);
			throw new RuntimeException("获取时光机数据异常");
		}
	}

	/**
	 * 
	 * 根据库中查询到的对象，生成时光机需要的vo
	 * 
	 * @param hire
	 *            入司信息
	 * @param firstSale
	 *            首单信息
	 * @param totalSale
	 *            总销售信息
	 * @param expensiveSale
	 *            16年最贵订单信息
	 * @param categoryInfo
	 *            16年销售按类目分组
	 * @param memberInfos
	 *            16年接待的会员信息
	 * @return
	 */
	private TimeMachineVo generateTimeMachineVo(EmployeeHireInfo hire, EmployeeFirstSaleInfo firstSale, EmployeeTotalSaleInfo totalSale, EmployeeExpensiveSaleInfo expensiveSale,
			EmployeeCategoryInfo categoryInfo, List<EmployeeMemberInfo> memberInfos, CouponInfoVo couponVo) {

		TimeMachineVo timeMachine = new TimeMachineVo();

		if (hire == null) {
			return timeMachine;
		}

		HandleFillVo handFillVo = new HandleFillVo();
		// 设置用户信息
		timeMachine.setUserInfo(handFillVo.fillHireVo(hire));

		// 设置券信息
		timeMachine.setCouponVo(couponVo);

		// 设置总销售信息
		timeMachine.setAllSaleInfo(handFillVo.fillAllSaleInfoVo(firstSale, totalSale, hire));
		// 设置2016销售信息
		timeMachine.setThisYearSaleInfo(handFillVo.fillThisYearSaleInfoVo(expensiveSale, categoryInfo, memberInfos));

		return timeMachine;
	}

	/**
	 * 把数据塞入缓存，默认过期时间为到午夜0点
	 *
	 * @param employeeId
	 * @param data
	 */
	private void saveDateInCache(String employeeId, String data) {
		cacheUtils.setex(TMConstants.TIME_MACHINE_KEY + employeeId, TMConstants.EXPIRE_TIME, data);
	}

	/**
	 * 
	 * 查询当前时间，离半夜12点还有多少秒
	 *
	 */
	public int caculateOneDayLeftSecond() {
		DateTime now = new DateTime();
		DateTime end = now.toLocalDate().plusDays(1).toDateTimeAtStartOfDay();

		return Seconds.secondsBetween(now, end).getSeconds();
	}

	/**
	 * 查询易购账号
	 */
	public StoreManEbuyAccount findEbuyNoByEmployeeId(String employeeId) {
		String key = TMConstants.EBUY_NO_KEY + employeeId;
		String value = cacheUtils.get(key);
		StoreManEbuyAccount account = null;
		if (value != null) {
			account = gson.fromJson(value, StoreManEbuyAccount.class);
		} else {
			account = storeManRemoteService.queryStoreManEbuyAccount(employeeId);
			if (account != null) {
				cacheUtils.setex(key, 3600, gson.toJson(account));
			}
		}
		return account;
	}

	/**
	 * 
	 * 根据缓存里的数据，组合一些前端需要的数据
	 * 
	 * 销售状态，设置订单每月销售数据，设置老用户信息
	 *
	 * @param data
	 * @return
	 */
	private TimeMachineVo fillDataInCache(String data, String employeeId) {
		// data必然有值，才会到这一步的，故不判断tmVo不为null了
		TimeMachineVo tmVo = gson.fromJson(data, TimeMachineVo.class);
		// 用户信息没有，那么很多事情都进行不下去，直接返回null
		if (tmVo == null || tmVo.getUserInfo() == null) {
			return null;
		}
		EmployeeHireInfoVo userInfo = tmVo.getUserInfo();

		// 设置员工姓名
		String employeeName = userInfo.getName();
		// 当缓存中无员工姓名或者员工姓名等于工号的时候，调用第三方接口获取真实姓名
		if (StringUtils.isBlank(employeeName) || employeeId.equals(employeeName)) {
			Employee storeMan = employeeService.queryEmployeeBasicInfo(employeeId);
			employeeName = (storeMan != null) ? storeMan.getEmployeeName() : employeeId;
			userInfo.setName(employeeName);
		}

		// 设置易购账号
		if (StringUtils.isEmpty(userInfo.getEbuyNo())) {
			// 查询用户易购账号
			StoreManEbuyAccount account = findEbuyNoByEmployeeId(employeeId);
			String ebuyNo = (account != null) ? account.getMaskeEbuyNo() : StringUtils.EMPTY;
			userInfo.setEbuyNo(ebuyNo);
		}

		// 设置蓝瘦香菇状态 ,如果都是刚从ftp拉取文件的，则需要设置此状态
		if (tmVo.getAllSaleInfo() != null && tmVo.getAllSaleInfo().getTotal() != null) {
			// 总销售信息
			TotalSaleInfoVo totalSale = tmVo.getAllSaleInfo().getTotal();
			// 状态 0：蓝瘦香菇 ； 1：洪荒之力
			String state = totalSale.getState();
			// 入司到现在，每月销售订单笔数
			String orderNumPerMonth = totalSale.getOrderNumPerMonth();
			if (StringUtils.isEmpty(state)) {
				String amount = totalSale.getAmount();
				String hireDate = userInfo.getEntryDate();
				state = String.valueOf(NumberUtils.getSaleState(new Double(amount), hireDate));
				totalSale.setState(state);
			}
			// 平均每月订单笔数，每天都有可能变化，故每次都计算下
			if(totalSale.getOrderNum() != null && userInfo.getTotalMonth() != null){
				Integer orderNum = Integer.parseInt(totalSale.getOrderNum());
				Integer month = Integer.parseInt(userInfo.getTotalMonth());
				orderNumPerMonth = NumberUtils.divide(orderNum, month);
				totalSale.setOrderNumPerMonth(orderNumPerMonth);
			}
		}

		// 设置老用户信息
		ThisYearSaleInfoVo thisYearSaleInfo = tmVo.getThisYearSaleInfo();
		// 存在2016年的销售数据
		if (thisYearSaleInfo != null) {
			// 2016接待老用户的key
			String key = TMConstants.TIME_MACHINE_MEMBER_KEY + employeeId;
			// 取出所有接待的老用户
			List<String> memberInfos = cacheUtils.lrange(key, 0, -1);

			LOGGER.debug("{}对应的老用户为：{}", employeeId, gson.toJson(memberInfos));
			// 从老用户redis key中获取,如果redis没有，从库里取，每天都会更新的
			List<MemberInfoVo> list = changeMemberInfoFromStr(memberInfos, employeeId);

			// 没数据；其实这种情况不存在，thisYearSaleInfo!=null,则memberInfos必须要有值的
			if (list == null) {
				// 那么统计数据中接待的老用户数据为0
				thisYearSaleInfo.getStatictisInfo().setCustomerNum("0");
			} else {
				// list里面每条数据的allMemberNum 与 oldMemberNum都一样，任取一条记录，计算接待比例
				// 总用户数
				String allMemberNum = list.get(0).getAllMemberNum();
				// 老用户数
				String oldMemberNum = list.get(0).getOldMemberNum();
				LOGGER.debug("allMemberNum:{},oldMemberNum:{}", allMemberNum, oldMemberNum);
				if (StringUtils.isNotEmpty(allMemberNum) && StringUtils.isNotEmpty(oldMemberNum)) {
					// 计算老用户占比
					String oldCustomPercent = NumberUtils.calculatePercent(Long.parseLong(oldMemberNum), Long.parseLong(allMemberNum));
					tmVo.getThisYearSaleInfo().setOldCustomerPercent(oldCustomPercent);
					// 2016总共接待多少用户
					thisYearSaleInfo.getStatictisInfo().setCustomerNum(allMemberNum);
				}
				// 根据销售订单数量，倒叙排列，最多取前5条记录
				Collections.sort(list);
				if (list.size() > 5) {
					// 取前5条记录
					list = list.subList(0, 5);
				}
				// 删除记录数为1的数据
				deleteInvalidCustomData(list);
				thisYearSaleInfo.setOldCustomer(list);
			}
		}
		// 没有券信息
		if (tmVo.getCouponVo() == null || tmVo.getCouponVo().getName() == null) {
			try {
				CouponInfoVo couponVo = new TaskG(innerCouponService, employeeId).call();
				tmVo.setCouponVo(couponVo);
			} catch (Exception e) {
				LOGGER.error("获取优惠券信息异常", e);
			}
		}

		return tmVo;
	}

	/**
	 * 将redis里面的老用户数据转换成vo对象，如果没有数据，则去库里查一次
	 * 
	 * @return
	 */
	private List<MemberInfoVo> changeMemberInfoFromStr(List<String> memberInfos, String employeeId) {
		// 缓存没有，从库中获取，库里没有，再返回null
		if (CollectionUtils.isEmpty(memberInfos)) {

			List<EmployeeMemberInfo> memberList = timeMachineDao.queryEmployeeMembersByEmployeeId(employeeId);
			if (CollectionUtils.isEmpty(memberList)) {
				return null;
			}
			HandleFillVo handFillVo = new HandleFillVo();
			return handFillVo.fillMemberInfoVo(memberList);
		}
		List<MemberInfoVo> list = new ArrayList<MemberInfoVo>();
		for (String memberInfoStr : memberInfos) {
			MemberInfoVo m = gson.fromJson(memberInfoStr, MemberInfoVo.class);
			list.add(m);
		}
		return list;
	}

	/**
	 * 只买过一笔订单的用户干掉，不是老用户
	 */
	private void deleteInvalidCustomData(List<MemberInfoVo> list) {
		for (Iterator<MemberInfoVo> iter = list.iterator(); iter.hasNext();) {
			// 订单数量为1，不算老客户
			if (TMConstants.ONE.equals(iter.next().getNum())) {
				iter.remove();
			}
		}
	}
}
